package distributed_lock

import (
	"context"
	"sync"
	"time"
)

const (
	NativeDefaultValue = "native"
)

// NativeLock 本地的锁，理论来说，这个锁只能按照指定的key锁住本机器上的功能，且没有自动的过期时间，需要手动释放
type NativeLock struct {
	lock   sync.RWMutex // 保证并发安全
	keyMap map[string]string
}

func NewNativeLock() *NativeLock {
	return &NativeLock{
		keyMap: make(map[string]string),
	}
}
func (n *NativeLock) TryLock(_ context.Context, key string, _, waitTime time.Duration) (bool, error) {
	if waitTime <= 0 {
		waitTime = DefaultRetryDelayTimes
	}

	for i := 0; i < int(waitTime/DefaultRetryDelayTimes); i++ {
		locked, err := n.lockKey(key)
		if locked || err != nil {
			return locked, err
		}
		time.Sleep(DefaultRetryDelayTimes)
	}
	return false, nil

}

func (n *NativeLock) lockKey(key string) (bool, error) {
	n.lock.RLock()
	_, ok := n.keyMap[key]
	n.lock.RUnlock()
	if !ok {
		n.lock.Lock()
		// 再次检查一次是否存在，如果存在，加锁失败
		if _, ok2 := n.keyMap[key]; ok2 {
			return false, nil
		}
		n.keyMap[key] = NativeDefaultValue
		n.lock.Unlock()
		return true, nil
	}
	return false, nil
}

func (n *NativeLock) UnLock(_ context.Context, key string) (bool, error) {
	n.lock.RLock()
	_, ok := n.keyMap[key]
	n.lock.RUnlock()
	if !ok {
		return true, nil
	}
	n.lock.Lock()
	delete(n.keyMap, key)
	n.lock.Unlock()
	return true, nil
}

func (n *NativeLock) RefreshLock(ctx context.Context, key string, expireTime time.Duration) (bool, error) {
	_, ok := n.keyMap[key]
	if ok {
		return true, nil
	}
	return false, nil
}

var _ DistributedLock = &NativeLock{}
